package jp.co.nes.awssupport.access.dao;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import jp.co.nes.awssupport.common.base.CommonException;
import jp.co.nes.awssupport.common.bean.CampaignAssignedBean;
import jp.co.nes.awssupport.common.dao.BaseJdbcDao;
import jp.co.nes.awssupport.common.dao.BeanProcessorEx;
import jp.co.nes.awssupport.common.utility.DateUtil;
import jp.co.nes.awssupport.common.utility.DbConnUtil;

/**
 * キャンペーン適用DAOです。
 */
public class CampaignAssignedDao extends BaseJdbcDao<CampaignAssignedBean> {

    /** キャンペーン適用を検索する際のSelect文 */
    private static final String SEL = ""
            + "select LinkedAccountId,"
            + "       YearMonth,"
            + "       AssignedPlanId,"
            + "       AssignedGroupId,"
            + "       AssignedCampaignName,"
            + "       TargetAmount, "
            + "       CampaignAmount"
            + "  from campaign_assigned"
            + " where LinkedAccountId = ?"
            + "   and YearMonth = ?"
            + " order by AssignedCampaignName";

    /** キャンペーン適用を検索する際のSelect文 */
    private static final String SEL_SUM = ""
            + "select sum(CampaignAmount) as CampaignAmount"
            + "  from campaign_assigned"
            + " where LinkedAccountId = ?"
            + "   and YearMonth = ?";

    /** キャンペーン適用を登録する際のInsert文 */
    private static final String BATCH_INS = ""
            + "insert into campaign_assigned ("
            + "    LinkedAccountId, "
            + "    YearMonth,"
            + "    AssignedPlanId,"
            + "    AssignedGroupId,"
            + "    AssignedCampaignName,"
            + "    TargetAmount, CampaignAmount)"
            + " values (?, ?, ?, ?, ?, ?, ?)";

    /** キャンペーン適用を削除する際に使用するDeletet文 */
    private static final String DEL_LINKEDACCOUNTID_YEARMONTH = ""
            + "delete from campaign_assigned"
            + " where LinkedAccountId = ?"
            + "   and YearMonth = ?";

    /**
     * デフォルトコンストラクタです。
     */
    public CampaignAssignedDao() {
    }

    /**
     * 引数に該当するキャンペーン適用の一覧を返却します。<br>
     * 該当するキャンペーン適用が存在しない場合は空リストを返却します。
     *
     * @param linkedAccountId 連結アカウントID
     * @param yearMonth 年月
     * @return キャンペーン適用の一覧
     */
    public List<CampaignAssignedBean> getList(String linkedAccountId, YearMonth yearMonth) {
        try {
            Connection connection = DbConnUtil.getConn();

            List<Object> paramList = new ArrayList<>();
            paramList.add(linkedAccountId);
            paramList.add(DateUtil.toInt(yearMonth));
            Object[] params = paramList.toArray();

            QueryRunner runner = new QueryRunner();
            return runner.query(connection, SEL,
                    new BeanListHandler<>(CampaignAssignedBean.class, new BasicRowProcessor(new BeanProcessorEx())),
                    params);
        } catch (SQLException e) {
            throw new CommonException(e);
        }
    }

    /**
     * 引数に該当するキャンペーン適用額の合計を返却します。<br>
     * 該当するキャンペーンが存在しない場合はnullを返却します。
     *
     * @param linkedAccountId 連結アカウントID
     * @param yearMonth 年月
     * @return キャンペーン適用額の合計
     */
    public Long getSumCampaignAmount(String linkedAccountId, YearMonth yearMonth) {
        try {
            Connection connection = DbConnUtil.getConn();

            List<Object> paramList = new ArrayList<>();
            paramList.add(linkedAccountId);
            paramList.add(DateUtil.toInt(yearMonth));
            Object[] params = paramList.toArray();

            // group byの集約はなし and 集計関数を使用しているので、常に1件存在する。
            // →該当データが存在しない場合は、nullになる。
            Long result = null;
            QueryRunner runner = new QueryRunner();
            BigDecimal sum = runner.query(connection, SEL_SUM, new ScalarHandler<BigDecimal>("CampaignAmount"), params);
            if (sum != null) {
                result = sum.longValue();
            }
            return result;
        } catch (SQLException e) {
            throw new CommonException(e);
        }
    }

    /**
     * 引数に該当する雑費適用を削除します。
     *
     * @param linkedAccountId 連結アカウントID
     * @param yearMonth 年月
     */
    public void delete(String linkedAccountId, YearMonth yearMonth) {
        try {
            Connection connection = DbConnUtil.getConn();

            Object[] params = new Object[2];
            params[0] = linkedAccountId;
            params[1] = DateUtil.toInt(yearMonth);

            QueryRunner runner = new QueryRunner();
            runner.update(connection, DEL_LINKEDACCOUNTID_YEARMONTH, params);
        } catch (SQLException e) {
            throw new CommonException(e);
        }
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.dao.BaseJdbcDao#getBatchInsQuery()
     */
    @Override
    protected String getBatchInsQuery() {
        return BATCH_INS;
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.dao.BaseJdbcDao#toBatchInsObjectList(jp.co.nes.awssupport.common.bean.BaseBean)
     */
    @Override
    protected List<Object> toBatchInsObjectList(CampaignAssignedBean bean) {
        List<Object> objectList = new ArrayList<>();
        objectList.add(bean.getLinkedAccountId());
        objectList.add(bean.getYearMonth());
        objectList.add(bean.getAssignedPlanId());
        objectList.add(bean.getAssignedGroupId());
        objectList.add(bean.getAssignedCampaignName());
        objectList.add(bean.getTargetAmount());
        objectList.add(bean.getCampaignAmount());
        return objectList;
    }
}
